package qr.server;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.simpleframework.xml.strategy.TreeStrategy;
import org.simpleframework.xml.strategy.Type;
import org.simpleframework.xml.stream.NodeMap;

import qr.server.managers.TransactionGateway;
import qr.core.Game;
import qr.core.Leaderboard;
import qr.core.Location;
import qr.core.LocationList;
import qr.core.Player;

@Path("/game")
public class RESTCore {
	
	private TransactionGateway database = TransactionGateway.getInstance();
	
	private static final TreeStrategy OBJECT_DB_CONVERTER = new TreeStrategy(){
		
        public boolean write(Type field, Object value, NodeMap node, Map map) {
            if( field.getType().getName().contains("objectdb") ){
        		node.put("class", field.getType().getName().replace("objectdb.", ""));
            }
            return false;
        } 
		
	};
	
	/**
	 * REST to fest all game. 
	 * @return - returns string of game names
	 */
	@GET 
	@Produces("application/xml")
	public String getGameName() { 
		Game game = database.getAllGames().get(0);
		
		return game.getGameName();
	}
	
	/**
	 * 
	 * @return - returns XML representation of leaderboard
	 */
	//Returns the leaderboard data for a game 
	//Verified Working 
	@GET 
	@Path("/leaderboard")
	@Produces("application/xml")
	public String getGameLeaderBoardData() { 
		Leaderboard board = database.getLeaderboard();
		return board.toXML();
	}
	
	//Returns the list of locations for a game 
	//Verified working
	@GET 
	@Path("/location")
	@Produces("application/xml")
	public String getGameLocations() { 
		Serializer s = new Persister(OBJECT_DB_CONVERTER);
		StringWriter sb = new StringWriter();
		try{
			LocationList l = new LocationList();
			l.c = database.getLocations();
			s.write(l, sb);
		}catch(Exception e){}
		return sb.getBuffer().toString();
	}
	
	//Returns the list of locations user has checked in 
	//Verified working
	@GET 
	@Path("/{user}/locations")
	@Produces("application/xml")
	public String getUserCheckedInLocation(@PathParam("user") String username) { 
		Player player = database.getPlayerWithUsername(username);
		LocationList l = new LocationList();
		l.c = player.getFoundLocation();
		Serializer s = new Persister(OBJECT_DB_CONVERTER);
		StringWriter sb = new StringWriter();
		try{
			s.write(l, sb);
		}catch(Exception e){}
		return sb.getBuffer().toString();
	}
	

	//Returns information for a location in the game 
	//Verified working
	@GET 
	@Path("/location/{id}")
	@Produces("application/xml")
	public String getLocationInformation(@PathParam("id") String id) { 
	
		long ID = (Long) Long.parseLong(id);
		Serializer s = new Persister(OBJECT_DB_CONVERTER);
		StringWriter sb = new StringWriter();
		try{
			s.write(database.getLocation(ID), sb);
		}catch(Exception e){}
		return sb.getBuffer().toString();
	}
	
	//Registers a new user to a game 
	//Verified Working
	@POST 
	@Path("/users/{user}")
	public Response registerUsertoGame(@PathParam("user") String username) { 
		
		Player player = new Player(username);
		if (database.hasPlayerInCurrentGame(player)) {
			return Response.status(403).entity("Sorry, user is already registered.").build();
		}
		
		database.registerPlayer(player);
		return Response.status(201).entity("User has been succesfully registered to the game").build();
	}
	
	//User checking in at a location { 
	//Verified Working
	@POST
	@Path("/location/{user}")
	public Response checkInToLocaton(String locationID, @PathParam("user") String user) { 
			
		Location location = null;
		long ID = (Long) Long.parseLong(locationID);
		Player player = database.getPlayerWithUsername(user);
		try { 
			location = database.getLocation(ID);
		} catch (RuntimeException excep) { 
			return Response.status(404).entity("Sorry, check in is not a location in the game").build();
		}	
		database.checkInPlayer(player, location);
		return Response.status(201).entity("User has succesfully checked in to location.").build();
	}	
}